package com.lanyou.cook.web;

import java.text.Collator;
import java.util.Comparator;
import java.util.List;
import java.util.TreeSet;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Tuple;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Root;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.lanyou.cook.common.Constants;
import com.lanyou.cook.entity.domain.Field;
import com.lanyou.cook.entity.domain.FieldSystem;
import com.lanyou.cook.entity.domain.SystemInterface;
import com.lanyou.cook.entity.domain.userManagement.User;
import com.lanyou.cook.service.security.UserSessionService;
import com.lanyou.cook.util.gson.GsonUtil;
import com.lanyou.cook.web.param.TreeNode;

/**
 * 领域、领域系统、接口关系展现的控制层
 * @author 仇伟业
 *
 */
@RestController
public class TreeController {
	@PersistenceContext
	private EntityManager entityManager;
	
	private String getLevel2Info(String userCode){
		CriteriaBuilder cb = entityManager.getCriteriaBuilder();
		CriteriaQuery<Tuple> cq = cb.createTupleQuery();
		
		// 构建FROM和JOIN部分
		Root<Field> rootField = cq.from(Field.class);
		Join<Field, FieldSystem> joinFieldSystem = rootField.join("fieldSystems", JoinType.LEFT);
		
		if(StringUtils.isNotEmpty(userCode)){
			Join<FieldSystem, User> joinUser = joinFieldSystem.join("users");
			cq.where(cb.equal(joinUser.get("userCode"), userCode));
		}
		
		// 构建SELECT部分
		cq.multiselect(rootField.get("id").alias("fieldId"), rootField.get("name").alias("fieldName"),
				joinFieldSystem.get("id").alias("fieldSystemId"), joinFieldSystem.get("name").alias("fieldSystemName"));

		// 执行查询
		TypedQuery<Tuple> q = entityManager.createQuery(cq);
		List<Tuple> queryResult = q.getResultList();
		
		Collator chineseCmp = Collator.getInstance(java.util.Locale.CHINA);
		Comparator<TreeNode> comparator = Comparator.comparing(TreeNode::getText, chineseCmp);
		
		// 组建树形对象，利用TreeSet进行排序
		TreeSet<TreeNode> fieldNodes = new TreeSet<>(comparator);
		queryResult.forEach(tuple ->{
			String fieldId = tuple.get("fieldId", String.class);
			String fieldName = tuple.get("fieldName", String.class);
			String fieldSystemId = tuple.get("fieldSystemId", String.class);
			String fieldSystemName = tuple.get("fieldSystemName", String.class);
			
			TreeNode fieldNode = CollectionUtils.find(fieldNodes, n -> StringUtils.equals(fieldId, n.getId()));
			if(fieldNode == null){
				fieldNode = new TreeNode();
				fieldNode.setNodeType("field");
				fieldNode.setId(fieldId);
				fieldNode.setText(fieldName);
				fieldNode.setChildren(new TreeSet<>(comparator));
				
				fieldNodes.add(fieldNode);
			}
			
			if(fieldSystemId == null)
				return;
				
			TreeNode fieldSystemNode = new TreeNode();
			fieldSystemNode.setNodeType("fieldSystem");
			fieldSystemNode.setId(fieldSystemId);
			fieldSystemNode.setText(fieldSystemName);
			
			fieldNode.getChildren().add(fieldSystemNode);
		});
		
		return GsonUtil.getDefaultGson().toJson(fieldNodes);
	}
	
	private String getLevel3Info(String userCode){
		CriteriaBuilder cb = entityManager.getCriteriaBuilder();
		CriteriaQuery<Tuple> cq = cb.createTupleQuery();
		
		// 构建FROM和JOIN部分
		Root<Field> rootField = cq.from(Field.class);
		Join<Field, FieldSystem> joinFieldSystem = rootField.join("fieldSystems", JoinType.LEFT);
		Join<FieldSystem, SystemInterface> joinSystemInterface = joinFieldSystem.join("systemInterfaces", JoinType.LEFT);
		
		if(StringUtils.isNotEmpty(userCode)){
			Join<FieldSystem, User> joinUser = joinFieldSystem.join("users");
			cq.where(cb.equal(joinUser.get("userCode"), userCode));
		}
		
		// 构建SELECT部分
		cq.multiselect(rootField.get("id").alias("fieldId"), rootField.get("name").alias("fieldName"),
				joinFieldSystem.get("id").alias("fieldSystemId"), joinFieldSystem.get("name").alias("fieldSystemName")
				,joinSystemInterface.get("id").alias("interfaceId"), joinSystemInterface.get("jobName").alias("interfaceName"));

		// 执行查询
		TypedQuery<Tuple> q = entityManager.createQuery(cq);
		List<Tuple> queryResult = q.getResultList();
		
		Collator chineseCmp = Collator.getInstance(java.util.Locale.CHINA);
		Comparator<TreeNode> comparator = Comparator.comparing(TreeNode::getText, chineseCmp);
		
		// 组建树形对象，利用TreeSet进行排序
		TreeSet<TreeNode> fieldNodes = new TreeSet<>(comparator);
		queryResult.forEach(tuple ->{
			String fieldId = tuple.get("fieldId", String.class);
			String fieldName = tuple.get("fieldName", String.class);
			String fieldSystemId = tuple.get("fieldSystemId", String.class);
			String fieldSystemName = tuple.get("fieldSystemName", String.class);
			String interfaceId = tuple.get("interfaceId", String.class);
			String interfaceName = tuple.get("interfaceName", String.class);
			
			TreeNode fieldNode = CollectionUtils.find(fieldNodes, n -> StringUtils.equals(fieldId, n.getId()));
			if(fieldNode == null){
				fieldNode = new TreeNode();
				fieldNode.setNodeType("field");
				fieldNode.setId(fieldId);
				fieldNode.setText(fieldName);
				fieldNode.setChildren(new TreeSet<>(comparator));
				
				fieldNodes.add(fieldNode);
			}
			
			if(fieldSystemId == null)
				return;
			TreeNode fieldSystemNode = CollectionUtils.find(fieldNode.getChildren(), n -> StringUtils.equals(fieldSystemId, n.getId()));
			if(fieldSystemNode == null){
				fieldSystemNode = new TreeNode();
				fieldSystemNode.setNodeType("fieldSystem");
				fieldSystemNode.setId(fieldSystemId);
				fieldSystemNode.setText(fieldSystemName);
				fieldSystemNode.setChildren(new TreeSet<>(comparator));
				fieldNode.getChildren().add(fieldSystemNode);
			}
			
			if(interfaceId == null)
				return;
			TreeNode systemInterfaceNode = new TreeNode();
			systemInterfaceNode.setNodeType("systemInterface");
			systemInterfaceNode.setId(interfaceId);
			systemInterfaceNode.setText(interfaceName);
			fieldSystemNode.getChildren().add(systemInterfaceNode);
		});
		
		return GsonUtil.getDefaultGson().toJson(fieldNodes);
	}

	/**
	 * 以树形结构获取领域系统
	 * @return 类型:String 领域系统数据
	 */
	@RequestMapping(value = Constants.BASE_URL_API + "/tree/getFieldSystemsForEasyUiTree", produces = "application/json")
	public String getFieldSystemsForEasyUiTree() {
		return getLevel2Info(null);
	}
	
	/**
	 * 以树形结构获取当前登录用户可管理领域系统
	 * @return 类型:String 当前登录用户可管理领域系统数据
	 */
	@RequestMapping(value = Constants.BASE_URL_API + "/tree/getFieldSystemsOfCurrentUserCanManageForEasyUiTree", produces = "application/json")
	public String getFieldSystemsOfCurrentUserCanManageForEasyUiTree() {
		String currentUserCode = UserSessionService.getCurrentAuthenticatedUserCode();
		return getLevel2Info(currentUserCode);
	}
	
	/**
	 * 以树形结构获取领域系统接口
	 * @return 类型:String 领域系统接口数据
	 */
	@RequestMapping(value = Constants.BASE_URL_API + "/tree/getSystemInterfacesForEasyUiTree", produces = "application/json")
	public String getSystemInterfacesForEasyUiTree() {
		return getLevel3Info(null);
	}
	
	/**
	 * 以树形结构获取当前登录用户可管理的领域系统的接口
	 * @return 类型:String 当前登录用户可管理的领域系统的接口数据
	 */
	@RequestMapping(value = Constants.BASE_URL_API + "/tree/getSystemInterfacesOfCurrentUserCanManageForEasyUiTree", produces = "application/json")
	public String getSystemInterfacesOfCurrentUserCanManageForEasyUiTree() {
		String currentUserCode = UserSessionService.getCurrentAuthenticatedUserCode();
		return getLevel3Info(currentUserCode);
	}
	
	/**
	 * 以树形结构获取指定用户可管理的领域系统（用于Spoon）
	 * @return 类型:String 指定用户可管理领域系统数据
	 */
	@RequestMapping(value = Constants.BASE_URL_KETTLE_API + "/{userCode}/directorys", method = RequestMethod.GET, produces = "application/json")
	public String getDirectorysForKettle(@PathVariable String userCode) {
		CriteriaBuilder cb = entityManager.getCriteriaBuilder();
		CriteriaQuery<Tuple> cq = cb.createTupleQuery();
		
		// 构建FROM和JOIN部分
		Root<Field> rootField = cq.from(Field.class);
		Join<Field, FieldSystem> joinFieldSystem = rootField.join("fieldSystems", JoinType.LEFT);
		Join<FieldSystem, User> joinUser = joinFieldSystem.join("users");
		
		// 构建WHERE部分
		cq.where(cb.equal(joinUser.get("userCode"), userCode));
		
		// 构建SELECT部分
		cq.multiselect(rootField.get("id").alias("fieldId"), rootField.get("name").alias("fieldName"),
				rootField.get("kettleDirectory").get("id").alias("fieldKettleDirectoryId"),
				joinFieldSystem.get("id").alias("fieldSystemId"), joinFieldSystem.get("name").alias("fieldSystemName"),
				joinFieldSystem.get("kettleDirectory").get("id").alias("fieldSystemKettleDirectoryId"));

		// 执行查询
		TypedQuery<Tuple> q = entityManager.createQuery(cq);
		List<Tuple> queryResult = q.getResultList();
		
		Collator chineseCmp = Collator.getInstance(java.util.Locale.CHINA);
		Comparator<TreeNode> comparator = Comparator.comparing(TreeNode::getText, chineseCmp);
		
		TreeSet<TreeNode> fieldNodes = new TreeSet<>(comparator);
		queryResult.forEach(tuple ->{
			String fieldId = tuple.get("fieldId", String.class);
			String fieldName = tuple.get("fieldName", String.class);
			Long fieldKettleDirectoryId = tuple.get("fieldKettleDirectoryId", Long.class);
			String fieldSystemId = tuple.get("fieldSystemId", String.class);
			String fieldSystemName = tuple.get("fieldSystemName", String.class);
			Long fieldSystemKettleDirectoryId = tuple.get("fieldSystemKettleDirectoryId", Long.class);
			
			TreeNode fieldNode = CollectionUtils.find(fieldNodes, n -> StringUtils.equals(fieldId, n.getId()));
			if(fieldNode == null){
				fieldNode = new TreeNode();
				fieldNode.setId(fieldId);
				fieldNode.setText(fieldName);
				fieldNode.setKettleObjectId(fieldKettleDirectoryId);
				fieldNode.setChildren(new TreeSet<>(comparator));
				
				fieldNodes.add(fieldNode);
			}
			
			if(fieldSystemId == null)
				return;
				
			TreeNode fieldSystemNode = new TreeNode();
			fieldSystemNode.setId(fieldSystemId);
			fieldSystemNode.setText(fieldSystemName);
			fieldSystemNode.setKettleObjectId(fieldSystemKettleDirectoryId);
			
			fieldNode.getChildren().add(fieldSystemNode);
		});
		
		TreeNode root = new TreeNode();
		root.setKettleObjectId(0L);
		root.setText("/");
		root.setChildren(fieldNodes);
		
		return GsonUtil.getDefaultGson().toJson(root);
	}
	


}
